#ifndef __HAL_ADC__H_
#define __HAL_ADC__H_

#include "hal_common.h"

/*!
 * @brief Clock divider for the converter.
 */
typedef enum
{
    eADC_ClockDividerSel_1 = 0U, /*!< For divider 1 from the input clock to the module. */
    eADC_ClockDividerSel_2 = 1U, /*!< For divider 2 from the input clock to the module. */
    eADC_ClockDividerSel_4 = 2U, /*!< For divider 4 from the input clock to the module. */
    eADC_ClockDividerSel_8 = 3U, /*!< For divider 8 from the input clock to the module. */
} ADC_ClockDividerSel_T;

/*!
 * @brief Converter's resolution.
 */
typedef enum
{
    eADC_ResolutionBits_8  = 0U,  /*!< 8 bit resolution. */
    eADC_ResolutionBits_12 = 1U, /*!< 12 bit resolution. */
    eADC_ResolutionBits_10 = 2U, /*!< 10 bit resolution. */
} ADC_ResolutionBits_T;

/*!
 * @brief Conversion clock source.
 */
typedef enum
{
    eADC_ClockSourceSel_Alt0 = 0U, /*!< Alternate clock 1 (ADC_ALTCLK1). */
    eADC_ClockSourceSel_Alt1 = 1U, /*!< Un-available. */
    eADC_ClockSourceSel_Alt2 = 2U, /*!< Un-available. */
    eADC_ClockSourceSel_Alt3 = 3U, /*!< Un-available. */
} ADC_ClockSourceSel_T;

/*!
 * @brief Reference voltage source.
 */
typedef enum
{
    eADC_RefVoltSourceSel_Vref = 0U, /*!< For external pins pair of VrefH and VrefL. */
    eADC_RefVoltSourceSel_Valt = 1U, /*!< For alternate reference pair of ValtH and ValtL. */
} ADC_RefVoltSourceSel_T;

/*!
 * @brief Hardware average mode.
 */
typedef enum
{
    eADC_HardwareAverageCount4 = 0U,   /*!< For hardware average with 4 samples. */
    eADC_HardwareAverageCount8 = 1U,   /*!< For hardware average with 8 samples. */
    eADC_HardwareAverageCount16 = 2U,  /*!< For hardware average with 16 samples. */
    eADC_HardwareAverageCount32 = 3U,  /*!< For hardware average with 32 samples. */
    eADC_HardwareAverageDisabled = 4U, /*!< Disable the hardware average feature.*/
} ADC_HardwareAverageMode_T;

/*!
 * @brief Hardware compare mode.
 */
typedef enum
{
    eADC_HardwareCompareMode0 = 0U, /*!< x < value1. */
    eADC_HardwareCompareMode1 = 1U, /*!< x > value1. */
    eADC_HardwareCompareMode2 = 2U, /*!< if value1 <= value2, then x < value1 || x > value2;
                                         else, value1 > x > value2. */
    eADC_HardwareCompareMode3 = 3U, /*!< if value1 <= value2, then value1 <= x <= value2;
                                           else x >= value1 || x <= value2. */
} ADC_HardwareCompareMode_T;

/*!
 * @brief ADC converter trigger mode.
 */
typedef enum
{
    eADC_ConvTriggerBySoftware = 0U,
    eADC_ConvTriggerByHardware = 1U,
} ADC_ConvTrigger_T;

/*!
 * @brief Converter configuration.
 */
typedef struct
{
    ADC_RefVoltSourceSel_T RefVoltSource;          /*!< Select the reference voltage source. */
    ADC_ClockSourceSel_T   ClockSource;            /*!< Select the input clock source to converter. */
    ADC_ClockDividerSel_T  ClockDivider;           /*!< Select the divider of input clock source. */
    ADC_ResolutionBits_T   ResolutionBits;         /*!< Select the sample resolution mode. */
    uint32_t               SampleClockCount;       /*!< Select the sample clock count.
                                                        Add its value may improve the stability of the conversion result. */
} ADC_ConverterConfig_T;

/*!
 * @brief Hardware compare configuration.
 */
typedef struct
{
    ADC_HardwareCompareMode_T HardwareCompareMode; /*!< Select the hardware compare mode. */
    int16_t Value1;  /*!< Setting value1 for hardware compare mode. */
    int16_t Value2;  /*!< Setting value2 for hardware compare mode. */
} ADC_HardwareCompareConfig_T;

/*!
* @brief ADC conversion command.
*/
typedef struct
{
    uint32_t ConvChannelNum;
    bool enInterruptOnCovnDone;
} ADC_ConvCommand_T;

void     ADC_HAL_ConfigConverter(ADC_Type *base, ADC_ConverterConfig_T *config);
void     ADC_HAL_DoAutoCalibration(ADC_Type *base);
void     ADC_HAL_SetConvTriggerMode(ADC_Type *base, ADC_ConvTrigger_T trigger);
void     ADC_HAL_SetHardwareCompareMode(ADC_Type *base, ADC_HardwareCompareConfig_T *config);
void     ADC_HAL_SetHardwareAverageMode(ADC_Type *base, ADC_HardwareAverageMode_T mode);
void     ADC_HAL_EnableDMAOnChannelConvDone(ADC_Type *base, bool enable);
void     ADC_HAL_EnableContinuousConvMode(ADC_Type *base, bool enable);

void     ADC_HAL_SetChannelConvCmd(ADC_Type *base, uint32_t channelGroup, ADC_ConvCommand_T *cmd);
uint32_t ADC_HAL_GetChannelConvValue(ADC_Type *base, uint32_t channelGroup);
bool     ADC_HAL_IsChannelConvDone(ADC_Type *base, uint32_t channelGroup);

/*! @}*/

#endif /* __HAL_ADC__H_ */
